

#include "stdafx.h"
#include "pf_entitycontainer.h"

#include "pf_debug.h"
#include "pf_dimension.h"
#include "pf_layer.h"
#include "pf_line.h"
#include "pf_insert.h"
#include "pf_spline.h"
#include "pf_information.h"
#include "pf_graphicview.h"

bool PF_Container::autoUpdateBorders = true;

/**
 * Default constructor.
 *
 * @param owner True if we own and also delete the entities.
 */
PF_Container::PF_Container(PF_Container* parent,
                                       bool owner)
        : PF_Entity(parent) {

    autoDelete=owner;
        PF_DEBUG->print("PF_EntityContainer::PF_EntityContainer: "
		"owner: %d", (int)owner);
    subContainer = NULL;
    //autoUpdateBorders = true;
    entIdx = -1;
}


/**
 * Copy constructor. Makes a deep copy of all entities.
 */
/*
PF_EntityContainer::PF_EntityContainer(const PF_EntityContainer& ec)
 : PF_Entity(ec) {
	
}
*/



/**
 * Destructor.
 */
PF_Container::~PF_Container() {
    clear();
}



PF_Entity* PF_Container::clone() {
	PF_DEBUG->print("PF_EntityContainer::clone: ori autoDel: %d", 
                autoDelete);

    PF_Container* ec = new PF_Container(*this);
        ec->setOwner(autoDelete);
	
	PF_DEBUG->print("PF_EntityContainer::clone: clone autoDel: %d", 
                ec->isOwner());

    ec->detach();
    ec->initId();

    return ec;
}



/**
 * Detaches shallow copies and creates deep copies of all subentities.
 * This is called after cloning entity containers.
 */
void PF_Container::detach() {
    QList<PF_Entity*> tmp;
    bool autoDel = isOwner();
	PF_DEBUG->print("PF_EntityContainer::detach: autoDel: %d", 
		(int)autoDel);
    setOwner(false);

    // make deep copies of all entities:
    for (PF_Entity* e=firstEntity();
            e!=NULL;
            e=nextEntity()) {
        if (!e->getFlag(LX_Define::FlagTemp)) {
            tmp.append(e->clone());
        }
    }

    // clear shared pointers:
    entities.clear();
    setOwner(autoDel);

    // point to new deep copies:
    for (int i = 0; i < tmp.size(); ++i) {
        PF_Entity* e = tmp.at(i);
        entities.append(e);
        e->reparent(this);
    }
}



void PF_Container::reparent(PF_Container* parent) {
    PF_Entity::reparent(parent);

    // All sub-entities:
    for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
            e!=NULL;
            e=nextEntity(LX_Define::ResolveNone)) {
        e->reparent(parent);
    }
}



/**
 * Called when the undo state changed. Forwards the event to all sub-entities.
 *
 * @param undone true: entity has become invisible.
 *               false: entity has become visible.
 */
void PF_Container::undoStateChanged(bool undone) {

    PF_Entity::undoStateChanged(undone);

    // ! don't pass on to subentities. undo list handles them
    // All sub-entities:
    /*for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
            e!=NULL;
            e=nextEntity(LX_Define::ResolveNone)) {
    	e->setUndoState(undone);
}*/
}



void PF_Container::setVisible(bool v) {
    PF_DEBUG->print("PF_EntityContainer::setVisible: %d", v);
    PF_Entity::setVisible(v);

    // All sub-entities:
    for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
            e!=NULL;
            e=nextEntity(LX_Define::ResolveNone)) {
        PF_DEBUG->print("PF_EntityContainer::setVisible: subentity: %d", v);
        e->setVisible(v);
    }
}



/**
 * @return Total length of all entities in this container.
 */
double PF_Container::getLength() {
    double ret = 0.0;

    for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
            e!=NULL;
            e=nextEntity(LX_Define::ResolveNone)) {
        if (e->isVisible()) {
            double l = e->getLength();
            if (l<0.0) {
                ret = -1.0;
                break;
            } else {
                ret += l;
            }
        }
    }

    return ret;
}


/**
 * Selects this entity.
 */
bool PF_Container::setSelected(bool select) {
    // This entity's select:
    if (PF_Entity::setSelected(select)) {

        // All sub-entity's select:
        for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
                e!=NULL;
                e=nextEntity(LX_Define::ResolveNone)) {
            if (e->isVisible()) {
                e->setSelected(select);
            }
        }
        return true;
    } else {
        return false;
    }
}



/**
 * Toggles select on this entity.
 */
bool PF_Container::toggleSelected() {
    // Toggle this entity's select:
    if (PF_Entity::toggleSelected()) {

        // Toggle all sub-entity's select:
        /*for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
                e!=NULL;
                e=nextEntity(LX_Define::ResolveNone)) {
            e->toggleSelected();
    }*/
        return true;
    } else {
        return false;
    }
}



/**
 * Selects all entities within the given area.
 *
 * @param select True to select, False to deselect the entities.
 */
void PF_Container::selectWindow(PF_Vector v1, PF_Vector v2,
                                      bool select, bool cross) {

    bool included;

    for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
            e!=NULL;
            e=nextEntity(LX_Define::ResolveNone)) {

        included = false;

        if (e->isVisible()) {
            if (e->isInWindow(v1, v2)) {
                //e->setSelected(select);
                included = true;
            } else if (cross==true) {
                PF_Line l[] =
                    {
                        PF_Line(NULL, PF_LineAttribute(v1, PF_Vector(v2.x, v1.y))),
                        PF_Line(NULL, PF_LineAttribute(PF_Vector(v2.x, v1.y), v2)),
                        PF_Line(NULL, PF_LineAttribute(v2, PF_Vector(v1.x, v2.y))),
                        PF_Line(NULL, PF_LineAttribute(PF_Vector(v1.x, v2.y), v1))
                    };
                PF_VectorSolutions sol;

                if (e->isContainer()) {
                    PF_Container* ec = (PF_Container*)e;
                    for (PF_Entity* se=ec->firstEntity(LX_Define::ResolveAll);
                            se!=NULL && included==false;
                            se=ec->nextEntity(LX_Define::ResolveAll)) {

                        for (int i=0; i<4; ++i) {
                            sol = PF_Information::getIntersection(
                                      se, &l[i], true);
                            if (sol.hasValid()) {
                                included = true;
                                break;
                            }
                        }
                    }
                } else {
                    for (int i=0; i<4; ++i) {
                        sol = PF_Information::getIntersection(e, &l[i], true);
                        if (sol.hasValid()) {
                            included = true;
                            break;
                        }
                    }
                }
            }
        }

        if (included) {
            e->setSelected(select);
        }
    }
}



/**
 * Adds a entity to this container and updates the borders of this 
 * entity-container if autoUpdateBorders is true.
 */
void PF_Container::addEntity(PF_Entity* entity) {
    /*
       if (isDocument()) {
           PF_LayerList* lst = getDocument()->getLayerList();
           if (lst!=NULL) {
               PF_Layer* l = lst->getActive();
               if (l!=NULL && l->isLocked()) {
                   return;
               }
           }
       }
    */

    if (entity==NULL) {
        return;
    }

    if (entity->rtti()==LX_Define::EntityImage ||
            entity->rtti()==LX_Define::EntityHatch) {
        entities.prepend(entity);
    } else {
        entities.append(entity);
    }
    if (autoUpdateBorders) {
        adjustBorders(entity);
    }
}


/**
 * Inserts a entity to this container at the given position and updates 
 * the borders of this entity-container if autoUpdateBorders is true.
 */
void PF_Container::insertEntity(int index, PF_Entity* entity) {
    if (entity==NULL) {
        return;
    }

    entities.insert(index, entity);

    if (autoUpdateBorders) {
        adjustBorders(entity);
    }
}



/**
 * Replaces the entity at the given index with the given entity
 * and updates the borders of this entity-container if autoUpdateBorders is true.
 */
/*RLZ unused function
void PF_EntityContainer::replaceEntity(int index, PF_Entity* entity) {
//RLZ TODO: is needed to delete the old entity? not documented in Q3PtrList
//    investigate in qt3support code if reactivate this function.
    if (entity==NULL) {
        return;
    }

    entities.replace(index, entity);

    if (autoUpdateBorders) {
        adjustBorders(entity);
    }
}RLZ*/



/**
 * Removes an entity from this container and updates the borders of 
 * this entity-container if autoUpdateBorders is true.
 */
bool PF_Container::removeEntity(PF_Entity* entity) {
//RLZ TODO: in Q3PtrList if 'entity' is NULL remove the current item-> at.(entIdx)
//    and sets 'entIdx' in next() or last() if 'entity' is the last item in the list.
//    in LXCAD is never called with NULL
    bool ret = entities.removeOne(entity);
    if (autoDelete && ret) {
        delete entity;
    }
    if (autoUpdateBorders) {
        calculateBorders();
    }
    return ret;
}



/**
 * Erases all entities in this container and resets the borders..
 */
void PF_Container::clear() {
    if (autoDelete) {
        while (!entities.isEmpty())
            delete entities.takeFirst();
    } else
        entities.clear();
    resetBorders();
}


/**
 * Counts all entities (branches of the tree). 
 */
unsigned long int PF_Container::count() {
    return entities.size();
}


/**
 * Counts all entities (leaves of the tree). 
 */
unsigned long int PF_Container::countDeep() {
    unsigned long int c=0;

    for (PF_Entity* t=firstEntity(LX_Define::ResolveNone);
            t!=NULL;
            t=nextEntity(LX_Define::ResolveNone)) {
        c+=t->countDeep();
    }

    return c;
}



/**
 * Counts the selected entities in this container.
 */
unsigned long int PF_Container::countSelected() {
    unsigned long int c=0;

    for (PF_Entity* t=firstEntity(LX_Define::ResolveNone);
            t!=NULL;
            t=nextEntity(LX_Define::ResolveNone)) {

        if (t->isSelected()) {
            c++;
        }
    }

    return c;
}



/**
 * Adjusts the borders of this graphic (max/min values)
 */
void PF_Container::adjustBorders(PF_Entity* entity) {
    //PF_DEBUG->print("PF_EntityContainer::adjustBorders");
    //resetBorders();

    if (entity!=NULL) {
        // make sure a container is not empty (otherwise the border
        //   would get extended to 0/0):
        if (!entity->isContainer() || entity->count()>0) {
            minV = PF_Vector::minimum(entity->getMin(),minV);
            maxV = PF_Vector::maximum(entity->getMax(),maxV);
        }

        // Notify parents. The border for the parent might
        // also change TODO: Check for efficiency
        //if(parent!=NULL) {
        //parent->adjustBorders(this);
        //}
    }
}


/**
 * Recalculates the borders of this entity container.
 */
void PF_Container::calculateBorders() {
    PF_DEBUG->print("PF_EntityContainer::calculateBorders");

    resetBorders();
    for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
            e!=NULL;
            e=nextEntity(LX_Define::ResolveNone)) {

        PF_Layer* layer = e->getLayer();

        PF_DEBUG->print("PF_EntityContainer::calculateBorders: "
                        "isVisible: %d", (int)e->isVisible());

        if (e->isVisible() && (layer==NULL || !layer->isFrozen())) {
            e->calculateBorders();
            adjustBorders(e);
        }
    }

    PF_DEBUG->print("PF_EntityContainer::calculateBorders: size 1: %f,%f",
                    getSize().x, getSize().y);

    // needed for correcting corrupt data (PLANS.dxf)
    if (minV.x>maxV.x || minV.x>LX_DOUBLEMAX || maxV.x>LX_DOUBLEMAX
            || minV.x<LX_DOUBLEMIN || maxV.x<LX_DOUBLEMIN) {

        minV.x = 0.0;
        maxV.x = 0.0;
    }
    if (minV.y>maxV.y || minV.y>LX_DOUBLEMAX || maxV.y>LX_DOUBLEMAX
            || minV.y<LX_DOUBLEMIN || maxV.y<LX_DOUBLEMIN) {

        minV.y = 0.0;
        maxV.y = 0.0;
    }

    PF_DEBUG->print("PF_EntityCotnainer::calculateBorders: size: %f,%f",
                    getSize().x, getSize().y);

    //PF_DEBUG->print("  borders: %f/%f %f/%f", minV.x, minV.y, maxV.x, maxV.y);

    //printf("borders: %lf/%lf  %lf/%lf\n", minV.x, minV.y, maxV.x, maxV.y);
    //PF_Entity::calculateBorders();
}



/**
 * Recalculates the borders of this entity container including 
 * invisible entities.
 */
void PF_Container::forcedCalculateBorders() {
    //PF_DEBUG->print("PF_EntityContainer::calculateBorders");

    resetBorders();
    for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
            e!=NULL;
            e=nextEntity(LX_Define::ResolveNone)) {

        //PF_Layer* layer = e->getLayer();

        if (e->isContainer()) {
            ((PF_Container*)e)->forcedCalculateBorders();
        } else {
            e->calculateBorders();
        }
        adjustBorders(e);
    }

    // needed for correcting corrupt data (PLANS.dxf)
    if (minV.x>maxV.x || minV.x>LX_DOUBLEMAX || maxV.x>LX_DOUBLEMAX
            || minV.x<LX_DOUBLEMIN || maxV.x<LX_DOUBLEMIN) {

        minV.x = 0.0;
        maxV.x = 0.0;
    }
    if (minV.y>maxV.y || minV.y>LX_DOUBLEMAX || maxV.y>LX_DOUBLEMAX
            || minV.y<LX_DOUBLEMIN || maxV.y<LX_DOUBLEMIN) {

        minV.y = 0.0;
        maxV.y = 0.0;
    }

    //PF_DEBUG->print("  borders: %f/%f %f/%f", minV.x, minV.y, maxV.x, maxV.y);

    //printf("borders: %lf/%lf  %lf/%lf\n", minV.x, minV.y, maxV.x, maxV.y);
    //PF_Entity::calculateBorders();
}



/**
 * Updates all Dimension entities in this container and 
 * reposition their labels.
 */
void PF_Container::updateDimensions() {

    PF_DEBUG->print("PF_EntityContainer::updateDimensions()");

    //for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
    //        e!=NULL;
    //        e=nextEntity(LX_Define::ResolveNone)) {

    PF_Entity* e;
    for (int i = 0; i < entities.size(); ++i) {
        e = entities.at(i);
        if (PF_Information::isDimension(e->rtti())) {
            // update and reposition label:
            ((PF_Dimension*)e)->update(true);
        } else if (e->isContainer()) {
            ((PF_Container*)e)->updateDimensions();
        }
    }

    PF_DEBUG->print("PF_EntityContainer::updateDimensions() OK");
}



/**
 * Updates all Insert entities in this container.
 */
void PF_Container::updateInserts() {

    PF_DEBUG->print("PF_EntityContainer::updateInserts()");

    //for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
    //        e!=NULL;
    //        e=nextEntity(LX_Define::ResolveNone)) {
    PF_Entity* e;
    for (int i = 0; i < entities.size(); ++i) {
        e = entities.at(i);
        //// Only update our own inserts and not inserts of inserts
        if (e->rtti()==LX_Define::EntityInsert  /*&& e->getParent()==this*/) {
            ((PF_Insert*)e)->update();
        } else if (e->isContainer() && e->rtti()!=LX_Define::EntityHatch) {
            ((PF_Container*)e)->updateInserts();
        }
    }

    PF_DEBUG->print("PF_EntityContainer::updateInserts() OK");
}



/**
 * Renames all inserts with name 'oldName' to 'newName'. This is
 *   called after a block was rename to update the inserts.
 */
void PF_Container::renameInserts(const QString& oldName,
                                       const QString& newName) {
    PF_DEBUG->print("PF_EntityContainer::renameInserts()");

    //for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
    //        e!=NULL;
    //        e=nextEntity(LX_Define::ResolveNone)) {

    PF_Entity* e;
    for (int j = 0; j < entities.size(); ++j) {
        e = entities.at(j);
        if (e->rtti()==LX_Define::EntityInsert) {
            PF_Insert* i = ((PF_Insert*)e);
            if (i->getName()==oldName) {
                i->setName(newName);
            }
        } else if (e->isContainer()) {
            ((PF_Container*)e)->renameInserts(oldName, newName);
        }
    }

    PF_DEBUG->print("PF_EntityContainer::renameInserts() OK");

}



/**
 * Updates all Spline entities in this container.
 */
void PF_Container::updateSplines() {

    PF_DEBUG->print("PF_EntityContainer::updateSplines()");

    //for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
    //        e!=NULL;
    //        e=nextEntity(LX_Define::ResolveNone)) {
    PF_Entity* e;
    for (int i = 0; i < entities.size(); ++i) {
        e = entities.at(i);
        //// Only update our own inserts and not inserts of inserts
        if (e->rtti()==LX_Define::EntitySpline  /*&& e->getParent()==this*/) {
            ((PF_Spline*)e)->update();
        } else if (e->isContainer() && e->rtti()!=LX_Define::EntityHatch) {
            ((PF_Container*)e)->updateSplines();
        }
    }

    PF_DEBUG->print("PF_EntityContainer::updateSplines() OK");
}


/**
 * Updates the sub entities of this container. 
 */
void PF_Container::update() {
    //for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
    //        e!=NULL;
    //        e=nextEntity(LX_Define::ResolveNone)) {
    for (int i = 0; i < entities.size(); ++i) {
        entities.at(i)->update();
    }
}



/**
 * Returns the first entity or NULL if this graphic is empty.
 * @param level 
 */
PF_Entity* PF_Container::firstEntity(LX_Define::ResolveLevel level) {
    PF_Entity* e = NULL;
    entIdx = -1;
    switch (level) {
    case LX_Define::ResolveNone:
        if (!entities.isEmpty()) {
            entIdx = 0;
            return entities.first();
        }
        break;

    case LX_Define::ResolveAllButInserts: {
            subContainer=NULL;
            if (!entities.isEmpty()) {
                entIdx = 0;
                e = entities.first();
            }
            if (e!=NULL && e->isContainer() && e->rtti()!=LX_Define::EntityInsert) {
                subContainer = (PF_Container*)e;
                e = ((PF_Container*)e)->firstEntity(level);
                // emtpy container:
                if (e==NULL) {
                    subContainer = NULL;
                    e = nextEntity(level);
                }
            }
            return e;
        }
        break;

    case LX_Define::ResolveAll: {
            subContainer=NULL;
            if (!entities.isEmpty()) {
                entIdx = 0;
                e = entities.first();
            }
            if (e!=NULL && e->isContainer()) {
                subContainer = (PF_Container*)e;
                e = ((PF_Container*)e)->firstEntity(level);
                // emtpy container:
                if (e==NULL) {
                    subContainer = NULL;
                    e = nextEntity(level);
                }
            }
            return e;
        }
        break;
    }

	return NULL;
}



/**
 * Returns the last entity or \p NULL if this graphic is empty.
 *
 * @param level \li \p 0 Groups are not resolved
 *              \li \p 1 (default) only Groups are resolved
 *              \li \p 2 all Entity Containers are resolved
 */
PF_Entity* PF_Container::lastEntity(LX_Define::ResolveLevel level) {
    PF_Entity* e = NULL;
    entIdx = entities.size()-1;
    switch (level) {
    case LX_Define::ResolveNone:
        if (!entities.isEmpty())
            return entities.last();
        break;

    case LX_Define::ResolveAllButInserts: {
            if (!entities.isEmpty())
                e = entities.last();
            subContainer = NULL;
            if (e!=NULL && e->isContainer() && e->rtti()!=LX_Define::EntityInsert) {
                subContainer = (PF_Container*)e;
                e = ((PF_Container*)e)->lastEntity(level);
            }
            return e;
        }
        break;

    case LX_Define::ResolveAll: {
            if (!entities.isEmpty())
                e = entities.last();
            subContainer = NULL;
            if (e!=NULL && e->isContainer()) {
                subContainer = (PF_Container*)e;
                e = ((PF_Container*)e)->lastEntity(level);
            }
            return e;
        }
        break;
    }

	return NULL;
}


/**
 * Returns the next entity or container or \p NULL if the last entity 
 * returned by \p next() was the last entity in the container.
 */
PF_Entity* PF_Container::nextEntity(LX_Define::ResolveLevel level) {

//set entIdx pointing in next entity and check if is out of range
    ++entIdx;
    switch (level) {
    case LX_Define::ResolveNone:
        if ( entIdx < entities.size() )
            return entities.at(entIdx);
        break;

    case LX_Define::ResolveAllButInserts: {
            PF_Entity* e=NULL;
            if (subContainer!=NULL) {
                e = subContainer->nextEntity(level);
                if (e!=NULL) {
                    return e;
                } else {
                    if ( entIdx < entities.size() )
                        e = entities.at(entIdx);
                }
            } else {
                if ( entIdx < entities.size() )
                    e = entities.at(entIdx);
            }
            if (e!=NULL && e->isContainer() && e->rtti()!=LX_Define::EntityInsert) {
                subContainer = (PF_Container*)e;
                e = ((PF_Container*)e)->firstEntity(level);
                // emtpy container:
                if (e==NULL) {
                    subContainer = NULL;
                    e = nextEntity(level);
                }
            }
            return e;
        }
        break;

    case LX_Define::ResolveAll: {
            PF_Entity* e=NULL;
            if (subContainer!=NULL) {
                e = subContainer->nextEntity(level);
                if (e!=NULL) {
                    return e;
                } else {
                    if ( entIdx < entities.size() )
                        e = entities.at(entIdx);
                }
            } else {
                if ( entIdx < entities.size() )
                    e = entities.at(entIdx);
            }
            if (e!=NULL && e->isContainer()) {
                subContainer = (PF_Container*)e;
                e = ((PF_Container*)e)->firstEntity(level);
                // emtpy container:
                if (e==NULL) {
                    subContainer = NULL;
                    e = nextEntity(level);
                }
            }
            return e;
        }
        break;
    }
	return NULL;
}



/**
 * Returns the prev entity or container or \p NULL if the last entity 
 * returned by \p prev() was the first entity in the container.
 */
PF_Entity* PF_Container::prevEntity(LX_Define::ResolveLevel level) {
//set entIdx pointing in prev entity and check if is out of range
    --entIdx;
    switch (level) {

    case LX_Define::ResolveNone:
        if (entIdx >= 0)
            return entities.at(entIdx);
        break;
    
	case LX_Define::ResolveAllButInserts: {
            PF_Entity* e=NULL;
            if (subContainer!=NULL) {
                e = subContainer->prevEntity(level);
                if (e!=NULL) {
                    return e;
                } else {
                    if (entIdx >= 0)
                        e = entities.at(entIdx);
                }
            } else {
                if (entIdx >= 0)
                    e = entities.at(entIdx);
            }
            if (e!=NULL && e->isContainer() && e->rtti()!=LX_Define::EntityInsert) {
                subContainer = (PF_Container*)e;
                e = ((PF_Container*)e)->lastEntity(level);
                // emtpy container:
                if (e==NULL) {
                    subContainer = NULL;
                    e = prevEntity(level);
                }
            }
            return e;
        }

    case LX_Define::ResolveAll: {
            PF_Entity* e=NULL;
            if (subContainer!=NULL) {
                e = subContainer->prevEntity(level);
                if (e!=NULL) {
                    return e;
                } else {
                    if (entIdx >= 0)
                        e = entities.at(entIdx);
                }
            } else {
                if (entIdx >= 0)
                    e = entities.at(entIdx);
            }
            if (e!=NULL && e->isContainer()) {
                subContainer = (PF_Container*)e;
                e = ((PF_Container*)e)->lastEntity(level);
                // emtpy container:
                if (e==NULL) {
                    subContainer = NULL;
                    e = prevEntity(level);
                }
            }
            return e;
        }
    }
	return NULL;
}



/**
 * @return Entity at the given index or NULL if the index is out of range.
 */
PF_Entity* PF_Container::entityAt(int index) {
    if (entities.size() > index && index >= 0)
        return entities.at(index);
    else
        return NULL;
}



/**
 * @return Current index.
 */
/*RLZ unused
int PF_EntityContainer::entityAt() {
    return entIdx;
} RLZ unused*/


/**
 * Finds the given entity and makes it the current entity if found.
 */
int PF_Container::findEntity(PF_Entity* entity) {
    entIdx = entities.indexOf(entity);
    return entIdx;
}



/**
 * Returns the copy to a new iterator for traversing the entities.
 */
QListIterator<PF_Entity*> PF_Container::createIterator() {
    return QListIterator<PF_Entity*>(entities);
}



/**
 * @return The point which is closest to 'coord' 
 * (one of the vertexes)
 */
PF_Vector PF_Container::getNearestEndpoint(const PF_Vector& coord,
        double* dist) {

    double minDist = LX_DOUBLEMAX;  // minimum measured distance
    double curDist;                 // currently measured distance
    PF_Vector closestPoint(false);  // closest found endpoint
    PF_Vector point;                // endpoint found

    //QListIterator<PF_Entity> it = createIterator();
    //PF_Entity* en;
    //while ( (en = it.current()) != NULL ) {
    //    ++it;
    for (PF_Entity* en = firstEntity();
            en != NULL;
            en = nextEntity()) {

        if (en->isVisible()) {
            point = en->getNearestEndpoint(coord, &curDist);
            if (point.valid && curDist<minDist) {
                closestPoint = point;
                minDist = curDist;
                if (dist!=NULL) {
                    *dist = curDist;
                }
            }
        }
    }

    return closestPoint;
}



PF_Vector PF_Container::getNearestPointOnEntity(const PF_Vector& coord,
        bool onEntity, double* dist, PF_Entity** entity) {

    PF_Vector point(false);

    PF_Entity* e = getNearestEntity(coord, dist, LX_Define::ResolveNone);

    if (e!=NULL && e->isVisible()) {
        point = e->getNearestPointOnEntity(coord, onEntity, dist, entity);
    }

    return point;
}



PF_Vector PF_Container::getNearestCenter(const PF_Vector& coord,
        double* dist) {

    PF_Vector point(false);
    PF_Entity* closestEntity;

    //closestEntity = getNearestEntity(coord, NULL, LX_Define::ResolveAll);
    closestEntity = getNearestEntity(coord, NULL, LX_Define::ResolveNone);

    if (closestEntity!=NULL) {
        point = closestEntity->getNearestCenter(coord, dist);
    }

    return point;
}



PF_Vector PF_Container::getNearestMiddle(const PF_Vector& coord,
        double* dist) {

    PF_Vector point(false);
    PF_Entity* closestEntity;

    closestEntity = getNearestEntity(coord, NULL, LX_Define::ResolveNone);

    if (closestEntity!=NULL) {
        point = closestEntity->getNearestMiddle(coord, dist);
    }

    return point;


    /*
       double minDist = PF_MAXDOUBLE;  // minimum measured distance
       double curDist;                 // currently measured distance
       PF_Vector closestPoint;         // closest found endpoint
       PF_Vector point;                // endpoint found

       for (PF_Entity* en = firstEntity();
               en != NULL;
               en = nextEntity()) {

           if (en->isVisible()) {
               point = en->getNearestMiddle(coord, &curDist);
               if (curDist<minDist) {
                   closestPoint = point;
                   minDist = curDist;
                   if (dist!=NULL) {
                       *dist = curDist;
                   }
               }
           }
       }

       return closestPoint;
    */
}



PF_Vector PF_Container::getNearestDist(double distance,
        const PF_Vector& coord,
        double* dist) {

    PF_Vector point(false);
    PF_Entity* closestEntity;

    closestEntity = getNearestEntity(coord, NULL, LX_Define::ResolveNone);

    if (closestEntity!=NULL) {
        point = closestEntity->getNearestDist(distance, coord, dist);
    }

    return point;
}



/**
 * @return The intersection which is closest to 'coord' 
 */
PF_Vector PF_Container::getNearestIntersection(const PF_Vector& coord,
        double* dist) {

    double minDist = LX_DOUBLEMAX;  // minimum measured distance
    double curDist;                 // currently measured distance
    PF_Vector closestPoint(false); // closest found endpoint
    PF_Vector point;                // endpoint found
    PF_VectorSolutions sol;
    PF_Entity* closestEntity;

    closestEntity = getNearestEntity(coord, NULL, LX_Define::ResolveAll);

    if (closestEntity!=NULL) {
        for (PF_Entity* en = firstEntity(LX_Define::ResolveAll);
                en != NULL;
                en = nextEntity(LX_Define::ResolveAll)) {

            if (en->isVisible() && en!=closestEntity) {
                sol = PF_Information::getIntersection(closestEntity,
                                                      en,
                                                      true);

                for (int i=0; i<4; i++) {
                    point = sol.get(i);
                    if (point.valid) {
                        curDist = coord.distanceTo(point);

                        if (curDist<minDist) {
                            closestPoint = point;
                            minDist = curDist;
                            if (dist!=NULL) {
                                *dist = curDist;
                            }
                        }
                    }
                }
            }
        }
        //}
    }

    return closestPoint;
}



PF_Vector PF_Container::getNearestRef(const PF_Vector& coord,
        double* dist) {

    double minDist = LX_DOUBLEMAX;  // minimum measured distance
    double curDist;                 // currently measured distance
    PF_Vector closestPoint(false);  // closest found endpoint
    PF_Vector point;                // endpoint found

    for (PF_Entity* en = firstEntity();
            en != NULL;
            en = nextEntity()) {

        if (en->isVisible()) {
            point = en->getNearestRef(coord, &curDist);
            if (point.valid && curDist<minDist) {
                closestPoint = point;
                minDist = curDist;
                if (dist!=NULL) {
                    *dist = curDist;
                }
            }
        }
    }

    return closestPoint;
}


PF_Vector PF_Container::getNearestSelectedRef(const PF_Vector& coord,
        double* dist) {

    double minDist = LX_DOUBLEMAX;  // minimum measured distance
    double curDist;                 // currently measured distance
    PF_Vector closestPoint(false);  // closest found endpoint
    PF_Vector point;                // endpoint found

    for (PF_Entity* en = firstEntity();
            en != NULL;
            en = nextEntity()) {

        if (en->isVisible() && en->isSelected() && !en->isParentSelected()) {
            point = en->getNearestSelectedRef(coord, &curDist);
            if (point.valid && curDist<minDist) {
                closestPoint = point;
                minDist = curDist;
                if (dist!=NULL) {
                    *dist = curDist;
                }
            }
        }
    }

    return closestPoint;
}


double PF_Container::getDistanceToPoint(const PF_Vector& coord,
        PF_Entity** entity,
        LX_Define::ResolveLevel level,
        double solidDist) {

    PF_DEBUG->print("PF_EntityContainer::getDistanceToPoint");

    double minDist = LX_DOUBLEMAX;      // minimum measured distance
    double curDist;                     // currently measured distance
    PF_Entity* closestEntity = NULL;    // closest entity found
    PF_Entity* subEntity = NULL;

    //int k=0;
    for (PF_Entity* e = firstEntity(level);
            e != NULL;
            e = nextEntity(level)) {

        if (e->isVisible()) {
            PF_DEBUG->print("entity: getDistanceToPoint");
            PF_DEBUG->print("entity: %d", e->rtti());
            curDist = e->getDistanceToPoint(coord, &subEntity, level, solidDist);

            PF_DEBUG->print("entity: getDistanceToPoint: OK");

            if (curDist<minDist) {
                if (level!=LX_Define::ResolveAll) {
                    closestEntity = e;
                } else {
                    closestEntity = subEntity;
                }
                minDist = curDist;
            }
        }
    }

    if (entity!=NULL) {
        *entity = closestEntity;
    }
    PF_DEBUG->print("PF_EntityContainer::getDistanceToPoint: OK");

    return minDist;
}



PF_Entity* PF_Container::getNearestEntity(const PF_Vector& coord,
        double* dist,
        LX_Define::ResolveLevel level) {

    PF_DEBUG->print("PF_EntityContainer::getNearestEntity");

    PF_Entity* e = NULL;

    // distance for points inside solids:
    double solidDist = LX_DOUBLEMAX;
    if (dist!=NULL) {
        solidDist = *dist;
    }

    double d = getDistanceToPoint(coord, &e, level, solidDist);

    if (e!=NULL && e->isVisible()==false) {
        e = NULL;
    }

    // if d is negative, use the default distance (used for points inside solids)
    if (dist!=NULL) {
        *dist = d;
    }
    PF_DEBUG->print("PF_EntityContainer::getNearestEntity: OK");

    return e;
}



/**
 * Rearranges the atomic entities in this container in a way that connected
 * entities are stored in the right order and direction.
 * Non-recoursive. Only affects atomic entities in this container.
 * 
 * @retval true all contours were closed
 * @retval false at least one contour is not closed
 */
bool PF_Container::optimizeContours() {

    PF_DEBUG->print("PF_EntityContainer::optimizeContours");

    PF_Vector current(false);
    PF_Vector start(false);
    PF_Container tmp;

    bool changed = false;
    bool closed = true;

    for (uint ci=0; ci<count(); ++ci) {
        PF_Entity* e1=entityAt(ci);

        if (e1!=NULL && e1->isEdge() && !e1->isContainer() &&
                !e1->isProcessed()) {

            PF_AtomicEntity* ce = (PF_AtomicEntity*)e1;

            // next contour start:
            ce->setProcessed(true);
            tmp.addEntity(ce->clone());
            current = ce->getEndpoint();
            start = ce->getStartpoint();

            // find all connected entities:
            bool done;
            do {
                done = true;
                for (uint ei=0; ei<count(); ++ei) {
                    PF_Entity* e2=entityAt(ei);

                    if (e2!=NULL && e2->isEdge() && !e2->isContainer() &&
                            !e2->isProcessed()) {

                        PF_AtomicEntity* e = (PF_AtomicEntity*)e2;

                        if (e->getStartpoint().distanceTo(current) <
                                1.0e-4) {

                            e->setProcessed(true);
                            tmp.addEntity(e->clone());
                            current = e->getEndpoint();

                            done=false;
                        } else if (e->getEndpoint().distanceTo(current) <
                                   1.0e-4) {

                            e->setProcessed(true);
                            PF_AtomicEntity* cl = (PF_AtomicEntity*)e->clone();
                            cl->reverse();
                            tmp.addEntity(cl);
                            current = cl->getEndpoint();

                            changed = true;
                            done=false;
                        }
                    }
                }
                if (!done) {
                    changed = true;
                }
            } while (!done);

            if (current.distanceTo(start)>1.0e-4) {
                closed = false;
            }
        }
    }

    // remove all atomic entities:
    bool done;
    do {
        done = true;
        for (PF_Entity* en=firstEntity(); en!=NULL; en=nextEntity()) {
            if (!en->isContainer()) {
                removeEntity(en);
                done = false;
                break;
            }
        }
    } while (!done);

    // add new sorted entities:
    for (PF_Entity* en=tmp.firstEntity(); en!=NULL; en=tmp.nextEntity()) {
        en->setProcessed(false);
        addEntity(en->clone());
    }

    PF_DEBUG->print("PF_EntityContainer::optimizeContours: OK");
    return closed;
}


bool PF_Container::hasEndpointsWithinWindow(PF_Vector v1, PF_Vector v2) {
    for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
            e!=NULL;
            e=nextEntity(LX_Define::ResolveNone)) {
        if (e->hasEndpointsWithinWindow(v1, v2))  {
            return true;
        }
    }

    return false;
}


void PF_Container::move(PF_Vector offset) {
    for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
            e!=NULL;
            e=nextEntity(LX_Define::ResolveNone)) {
        e->move(offset);
    }
    if (autoUpdateBorders) {
        calculateBorders();
    }
}



void PF_Container::rotate(PF_Vector center, double angle) {
    for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
            e!=NULL;
            e=nextEntity(LX_Define::ResolveNone)) {
        e->rotate(center, angle);
    }
    if (autoUpdateBorders) {
        calculateBorders();
    }
}



void PF_Container::scale(PF_Vector center, PF_Vector factor) {
    if (fabs(factor.x)>PF_TOLERANCE && fabs(factor.y)>PF_TOLERANCE) {
        for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
                e!=NULL;
                e=nextEntity(LX_Define::ResolveNone)) {
            e->scale(center, factor);
        }
    }
    if (autoUpdateBorders) {
        calculateBorders();
    }
}



void PF_Container::mirror(PF_Vector axisPoint1, PF_Vector axisPoint2) {
    if (axisPoint1.distanceTo(axisPoint2)>1.0e-6) {
        for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
                e!=NULL;
                e=nextEntity(LX_Define::ResolveNone)) {
            e->mirror(axisPoint1, axisPoint2);
        }
    }
}


void PF_Container::stretch(PF_Vector firstCorner,
                                 PF_Vector secondCorner,
                                 PF_Vector offset) {

    if (getMin().isInWindow(firstCorner, secondCorner) &&
            getMax().isInWindow(firstCorner, secondCorner)) {

        move(offset);
    } else {
        for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
                e!=NULL;
                e=nextEntity(LX_Define::ResolveNone)) {
            e->stretch(firstCorner, secondCorner, offset);
        }
    }

    // some entitiycontainers might need an update (e.g. PF_Leader):
    update();
}



void PF_Container::moveRef(const PF_Vector& ref,
                                 const PF_Vector& offset) {

    for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
            e!=NULL;
            e=nextEntity(LX_Define::ResolveNone)) {
        e->moveRef(ref, offset);
    }
    if (autoUpdateBorders) {
        calculateBorders();
    }
}


void PF_Container::moveSelectedRef(const PF_Vector& ref,
        const PF_Vector& offset) {

    for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
            e!=NULL;
            e=nextEntity(LX_Define::ResolveNone)) {
        e->moveSelectedRef(ref, offset);
    }
    if (autoUpdateBorders) {
        calculateBorders();
    }
}



void PF_Container::draw(PF_Painter* painter, PF_GraphicView* view,
                              double /*patternOffset*/) {

    if (painter==NULL || view==NULL) {
        return;
    }

    for (PF_Entity* e=firstEntity(LX_Define::ResolveNone);
            e!=NULL;
            e = nextEntity(LX_Define::ResolveNone)) {

        view->drawEntity(painter, e);
    }
}


/**
 * Dumps the entities to stdout.
 */
std::ostream& operator << (std::ostream& os, PF_Container& ec) {

    static int indent = 0;

    char* tab = new char[indent*2+1];
    for(int i=0; i<indent*2; ++i) {
        tab[i] = ' ';
    }
    tab[indent*2] = '\0';

    ++indent;

    unsigned long int id = ec.getId();

    os << tab << "EntityContainer[" << id << "]: \n";
    os << tab << "Borders[" << id << "]: "
    << ec.minV << " - " << ec.maxV << "\n";
    //os << tab << "Unit[" << id << "]: "
    //<< PF_Units::unit2string (ec.unit) << "\n";
    if (ec.getLayer()!=NULL) {
        os << tab << "Layer[" << id << "]: "
        << ec.getLayer()->getName().toLatin1().data() << "\n";
    } else {
        os << tab << "Layer[" << id << "]: <NULL>\n";
    }
    //os << ec.layerList << "\n";

    os << tab << " Flags[" << id << "]: "
    << (ec.getFlag(LX_Define::FlagVisible) ? "LX_Define::FlagVisible" : "");
    os << (ec.getFlag(LX_Define::FlagUndone) ? " LX_Define::FlagUndone" : "");
    os << (ec.getFlag(LX_Define::FlagSelected) ? " LX_Define::FlagSelected" : "");
    os << "\n";


    os << tab << "Entities[" << id << "]: \n";
    for (PF_Entity* t=ec.firstEntity();
            t!=NULL;
            t=ec.nextEntity()) {

        switch (t->rtti()) {
        case LX_Define::EntityInsert:
            os << tab << *((PF_Insert*)t);
            os << tab << *((PF_Entity*)t);
            os << tab << *((PF_Container*)t);
            break;
        default:
            if (t->isContainer()) {
                os << tab << *((PF_Container*)t);
            } else {
                os << tab << *t;
            }
            break;
        }
    }
    os << tab << "\n\n";
    --indent;

    delete[] tab;
    return os;
}

